home *** CD-ROM | disk | FTP | other *** search
/ Mac Power 1997 December / MACPOWER-1997-12.ISO.7z / MACPOWER-1997-12.ISO / AMUG / PROGRAMMING / Raven 1.2.sit / Raven 1.2 / Source / Foundation / Common / ZNubEmbeddedSymbols.cpp < prev    next >
Text File  |  1997-05-24  |  23KB  |  765 lines

  1. /*
  2.  *  File:       ZNubEmbeddedSymbols.cpp
  3.  *  Summary:       Embedded Symbol Extraction (This is used by ZCrawl.cpp)
  4.  *  Written by: Apple Computer
  5.  *
  6.  *  Copyright ゥ 1995-1997 by Apple Computer, Inc., all rights reserved.
  7.  *
  8.  *  Change History (most recent first):    
  9.  *
  10.  *         <2>     5/24/97    JDJ        Turned on scheduling.
  11.  *         <1>     2/02/97    JDJ        Created (from Crawl.cpp in the OpenDoc utilities).
  12.  */
  13.  
  14. #include <ZNubEmbeddedSymbols.h>
  15.  
  16. #include <Errors.h>
  17. #include <String.h>
  18.  
  19.  
  20. #pragma peephole            on
  21. #pragma global_optimizer     on
  22. #pragma auto_inline            on
  23. #pragma  scheduling          603
  24.  
  25. #if powerc
  26. #pragma optimization_level    4
  27. #endif
  28.  
  29. //==============================================================================
  30. // Embedded Symbol Extraction (copied from debugger nub)
  31. //==============================================================================
  32.  
  33. #define kNoErr                    noErr
  34. #define PACKET_MAX_DATA_LENGTH    512
  35.  
  36. // max length of an embedded symbol (longer will be truncated)
  37. #define kMaxNameLength                        256
  38. #define kTTblMaxNameLength                    256
  39. #define kMaxTracebackNameSearchLength        512
  40.  
  41.  
  42.  
  43. // PowerPC embedded symbol stuff:
  44.  
  45. #define kMaxPwrPCFnLength    262144
  46. #define kMaxPwrPCFnInstrs    (kMaxPwrPCFnLength >> 2)
  47.  
  48. typedef struct TracebackTblEndAlt
  49.     {
  50.         ULongWord        unknown;
  51.         ULongWord        fnLength;
  52.         UWord            nameLength;
  53.         char            name[kTTblMaxNameLength];
  54.     } TracebackTblEndAlt;
  55.  
  56. typedef struct TracebackTblEnd
  57.     {
  58.         ULongWord        fnLength;
  59.         UWord            nameLength;
  60.         char            name[kTTblMaxNameLength];
  61.     } TracebackTblEnd;
  62.  
  63. typedef struct TracebackTbl
  64.     {
  65.         ULongWord            zero;
  66.         char                version;
  67.         char                language;
  68.         char                flags[6];
  69.         union {
  70.         TracebackTblEnd        end;    // if flags[4] == 0
  71.         TracebackTblEndAlt    endAlt;    // if flags[4] > 0
  72.         } u;
  73.     } TracebackTbl;
  74.  
  75.  
  76. static TracebackTbl *FindTracebackTbl (void *addr, TracebackTbl *ttbl, ReadMemFn readMemCallback, va_list args);
  77.  
  78.  
  79.  
  80. // 68K embedded symbol stuff:
  81.  
  82. #define kMax68KFnLength        32768
  83.  
  84. #define kLINKA6                0x4E56
  85. #define kJMPA0                0x4ED0
  86. #define kRTS                0x4E75
  87. #define kRTD                0x4E74
  88.  
  89.  
  90.  
  91. static UByte    *GetProcStart (UByte *addressOfFnEnd, ReadMemFn readMemCallback, va_list args);
  92. static UByte    *FindNextModule (UByte *start, UByte *limit, Boolean *hasName, ReadMemFn readMemCallback, va_list args);
  93. static Boolean    ValidName (UByte *name, ReadMemFn readMemCallback, va_list args);
  94. static void        GetModuleName (UByte *address, char *name, UByte **dataStart, UByte **dataEnd, ReadMemFn readMemCallback, va_list args);
  95. static Boolean    FindReturn (UByte *start, UByte *limit, UByte **afterReturn, ReadMemFn readMemCallback, va_list args);
  96. static Boolean    LegalSymbolChar (short ch);
  97. static Boolean    LegalTargetChar (short ch);
  98.  
  99. #pragma segment CodeTracking
  100.  
  101. #if GENERATINGPOWERPC
  102. //
  103. // Tries to find a traceback table for the routine in which addr is presumed to be.
  104. // If successful, returns the name of the routine in name and the addresses of the
  105. // beginning and end of the routine in fnBegin and fnEnd.  Else scans forward for
  106. // a blr instruction and backward for an mflr instruction to guesstimate fnBegin
  107. // and fnEnd, and leaves name empty.
  108. //
  109. OSErr LookupPowerPCSym (TargetAddress addr, char *name, TargetAddress *fnBegin, TargetAddress *fnEnd,
  110.         ReadMemFn readMemCallback, ...)
  111. {
  112.     va_list            args;
  113.     TracebackTbl    ttbl;
  114.     TracebackTbl    *where;
  115.     char            *namePtr;
  116.     UWord            nameLength;
  117.     ULongWord        codeStart, fnLength;
  118.     ULongWord        instr;
  119.     long            i, offset;
  120.  
  121.     va_start( args, readMemCallback );
  122.     
  123.     #define    kmflrInstr    0x7C0802A6
  124.     #define    kblrInstr    0x4E800020
  125.     
  126.     *fnBegin = addr;
  127.     *fnEnd = addr;
  128.  
  129.     where = FindTracebackTbl ((void*) addr, &ttbl, readMemCallback, args);
  130.  
  131.     if (where)
  132.     {
  133.         fnLength = ttbl.flags[4] ? ttbl.u.endAlt.fnLength : ttbl.u.end.fnLength;
  134.         codeStart = (ULongWord) where - fnLength;
  135.         offset = addr - codeStart;
  136.         if (offset >= 0)
  137.         {
  138.             namePtr = ttbl.flags[4] ? ttbl.u.endAlt.name : ttbl.u.end.name;
  139.             nameLength = ttbl.flags[4] ? ttbl.u.endAlt.nameLength : ttbl.u.end.nameLength;
  140.             if (nameLength > kMaxNameLength - 2)
  141.                 // leave room for leading length byte and terminating null
  142.                 nameLength = kMaxNameLength - 2;
  143.             strncpy (&name[1], namePtr, nameLength);
  144.             name[0] = nameLength;            // now it's a Pascal string
  145.             name[nameLength + 1] = 0;        // terminating null to make it a TProtocolString
  146.             if (nameLength & 1)                // do we need a pad byte?
  147.                 name[nameLength + 2] = 0;    // add one
  148.             *fnBegin = (TargetAddress) codeStart;
  149.             *fnEnd = (TargetAddress) where;
  150.             return kNoErr;
  151.         }
  152.     }
  153.  
  154.     // couldn't find a traceback, so no embedded name, but we'll scan for the fn boundaries anyway
  155.     for (i = 0; i < kMaxPwrPCFnInstrs; ++i)
  156.     {
  157.         if ((*readMemCallback) ((void*) *fnBegin, 4, &instr, args) != kNoErr)
  158.             return kSymbolNotFound;
  159.         if (instr == kmflrInstr)
  160.             break;
  161.         else if (instr == kblrInstr)
  162.             {
  163.             // probably a leaf routine, and we've backed up into the preceding fn
  164.             *fnBegin += 4;
  165.             break;
  166.             }
  167.         *fnBegin -= 4;
  168.     }
  169.     
  170.     if (i == kMaxPwrPCFnInstrs)
  171.     {
  172.         // didn't find the fn begin
  173.         *fnBegin = addr;
  174.         *fnEnd = addr;
  175.         return kSymbolNotFound;
  176.     }
  177.  
  178.     // found the fn begin, now try to find the fn end
  179.     for (i = 0; i < kMaxPwrPCFnInstrs; ++i)
  180.     {
  181.         if ((*readMemCallback) ((void*) *fnEnd, 4, &instr, args) != kNoErr)
  182.             return kSymbolNotFound;
  183.         *fnEnd += 4;
  184.         if (instr == kblrInstr)
  185.             break;
  186.     }
  187.     
  188.     if (i == kMaxPwrPCFnInstrs)
  189.     {
  190.         // didn't find the fn end
  191.         *fnBegin = addr;
  192.         *fnEnd = addr;
  193.         return kSymbolNotFound;
  194.     }
  195.     
  196.     return kNoErr;
  197. }
  198.  
  199.  
  200. //
  201. // Tries to find a traceback table for the routine in which addr is presumed to be.  If
  202. // successful, returns a pointer to the traceback table and copies its contents into ttbl.
  203. // If not successful, returns NULL.
  204. //
  205. static TracebackTbl *FindTracebackTbl (void *addr, TracebackTbl *ttbl, ReadMemFn readMemCallback, va_list args)
  206. {
  207.     ULongWord        where = (ULongWord) addr;
  208.     ULongWord        i, memLongWord, fnLength;
  209.     char            *name;
  210.     UWord            nameLength;
  211.     
  212.     for (i = 0; i < kMaxPwrPCFnLength; i += 4)
  213.     {
  214.         if ((*readMemCallback) ((void *) where, 4, &memLongWord, args) != kNoErr)
  215.             return NULL;
  216.         if (memLongWord == 0)
  217.             break;
  218.         where += 4;
  219.     }
  220.     
  221.     if (i == kMaxPwrPCFnLength)
  222.         return NULL;
  223.  
  224.     if ((*readMemCallback) ((void *) where, sizeof(TracebackTbl), ttbl, args) != kNoErr)
  225.         return NULL;
  226.     
  227.     // now for some sanity checks
  228.     fnLength = ttbl->flags[4] ? ttbl->u.endAlt.fnLength : ttbl->u.end.fnLength;
  229.     name = ttbl->flags[4] ? ttbl->u.endAlt.name : ttbl->u.end.name;
  230.     nameLength = ttbl->flags[4] ? ttbl->u.endAlt.nameLength : ttbl->u.end.nameLength;
  231.     if ((fnLength > kMaxPwrPCFnLength) || (nameLength > kMaxTracebackNameSearchLength) || (name[0] < ' ') || (name[0] > '}'))
  232.         return NULL;
  233.     else
  234.         return (TracebackTbl *) where;
  235. }
  236. #endif /*GENERATINGPOWERPC*/
  237.  
  238. //
  239. // Tries to find a Macsbug symbol for the routine in which addr is presumed to be.
  240. // If successful, returns the name of the routine in name and the addresses of the
  241. // beginning and end of the routine in fnBegin and fnEnd.
  242. // Name is a "PC" string (a Pascal string with a terminating null).
  243. // fnBegin should normally always be less than or equal to addr, but if addr happens
  244. // to be somewhere strange (like in an embedded symbol itself!), we may actually
  245. // find the next function.
  246. //
  247. OSErr Lookup68KSym (TargetAddress addr, char *name, TargetAddress *fnBegin, TargetAddress *fnEnd,
  248.         ReadMemFn readMemCallback, ...)
  249. {
  250.     va_list            args;
  251.     UByte*            address = (UByte*) addr;
  252.     UByte*            limit = (UByte*) (addr + kMax68KFnLength);
  253.     UByte*            addressOfFnEnd;
  254.     UByte*            codeStart;
  255.     UByte*            ignore1;
  256.     UByte*            ignore2;
  257.     Boolean            hasName;
  258.  
  259.     va_start( args, readMemCallback );
  260.     
  261.     addressOfFnEnd = FindNextModule (address, limit, &hasName, readMemCallback, args);
  262.     
  263.     if (addressOfFnEnd)
  264.         {
  265.         //    10/18/94 dkk
  266.         //    Code here used to search backwards from the end of the function to find the start of this function.
  267.         //    If the start of the function wasn't before the address we were interested in finding the symbol for
  268.         //    then we searched again from the original address. We then would search forward again for the end of
  269.         //    the function. This seemed like a lot of extra work. I changed the code look for the start of the
  270.         //    function from the original start address, and don't look for the end of function twice.
  271.         //    We've found a module for the address, find the start of the procedure.
  272.         //
  273.         codeStart = GetProcStart (address, readMemCallback, args);
  274.  
  275.         if (hasName)
  276.             GetModuleName (addressOfFnEnd, name, &ignore1, &ignore2, readMemCallback, args);
  277.         else
  278.             *name = 0;
  279.             
  280.         *fnBegin = (TargetAddress) codeStart;
  281.         *fnEnd = (TargetAddress) addressOfFnEnd;
  282.         return kNoErr;
  283.         }
  284.     
  285.     *fnBegin = addr;
  286.     *fnEnd = addr + kMax68KFnLength;
  287.     return kSymbolNotFound;
  288. }
  289.  
  290.  
  291. //    
  292. //    GetProcStart
  293. //
  294. //        Search backwards for the start of the procedure and return its address.
  295. //
  296. //        10/18/94 - dkk
  297. //        This code was pulled from MacsBug, which didn't suffer any overhead hit from reading one word of memory
  298. //        at a time. Since when MacsBug is executing, it always has its own bus error handler installed, there
  299. //        is no need to install a special handler for each memory access. For the nubs, this is not the case.
  300. //        Each memory access require installation and removal of the bus error handler. For this reason, this code
  301. //        was changes to read a buffer at a time, and step through the buffer. In addition the check for RTS,
  302. //        JMP (A0), and RTD were moved to here, even though this duplicateds code in FindNextModule. FindNextModule
  303. //        will also do the check, but another memory access is required to do the check. By checking here first,
  304. //        we save the overhead of that memory access most of the time.
  305.  
  306. static UByte *GetProcStart (UByte *addressOfFnEnd, ReadMemFn readMemCallback, va_list args)
  307. {
  308.     UWord        instr;
  309.     UByte        *codeStart;
  310.     UByte        *limit = NULL;
  311.     UByte        *prevDataStart;
  312.     char        prevProcName[kMaxNameLength];
  313.     char        memBuffer[PACKET_MAX_DATA_LENGTH];
  314.     short        offset;
  315.     Boolean        hasName;
  316.  
  317.     if ((ULongWord) addressOfFnEnd >= (ULongWord) kMax68KFnLength)
  318.         limit = addressOfFnEnd - kMax68KFnLength;
  319.  
  320.     codeStart = addressOfFnEnd - 2 - (PACKET_MAX_DATA_LENGTH - 2);
  321.     
  322.     if ((*readMemCallback) ((void *) codeStart, PACKET_MAX_DATA_LENGTH, memBuffer, args) != kNoErr)
  323.         return NULL;
  324.     offset = PACKET_MAX_DATA_LENGTH - 2;
  325.     instr = *(short *) &memBuffer[offset];
  326.  
  327.     //    RTD is a 4 byte instruction. RTS and JMP (A0) are 2 byte instructions.
  328.     //
  329.     if ((instr != kRTS) && (instr != kJMPA0))
  330.         offset -= 2;
  331.  
  332.     //    Step backwards looking for the start of the procedure.
  333.     //
  334.     while (codeStart > limit /* gCurBlock.data */)
  335.         {
  336.         offset -= 2;
  337.  
  338.         if (offset < 0)
  339.         {
  340.             codeStart -= PACKET_MAX_DATA_LENGTH;
  341.             offset = PACKET_MAX_DATA_LENGTH - 2;
  342.             if ((*readMemCallback) ((void *) codeStart, PACKET_MAX_DATA_LENGTH, memBuffer, args) != kNoErr)
  343.                 return NULL;
  344.         }
  345.         instr = *(short *) &memBuffer[offset];
  346.  
  347.         //    LinkA6 starts a procedure.
  348.         //
  349.         if (instr == kLINKA6)
  350.             return (codeStart + offset);
  351.  
  352.         if ((instr == kJMPA0) || (instr == kRTS) || (instr == kRTD))
  353.             {
  354.             addressOfFnEnd = FindNextModule (codeStart + offset, codeStart + offset + 2, &hasName, readMemCallback, args);
  355.             if (addressOfFnEnd)
  356.                 {
  357.                 // Found the previous procedure. Its dataEnd is the same as the codeStart we are looking for.
  358.                 //    10/18/94 dkk
  359.                 //    This used to call GetModuleName all the time. Can save the overhead of determining the module
  360.                 //    name again, by checking hasName returned from FindNextModule.
  361.                 //
  362.                 if (hasName)
  363.                     {
  364.                     GetModuleName (addressOfFnEnd, prevProcName, &prevDataStart, &codeStart, readMemCallback, args);
  365.                     return (codeStart);
  366.                     }
  367.                 else
  368.                     return (addressOfFnEnd);
  369.                 }
  370.             }
  371.         }
  372.     return NULL /* (gCurBlock.data) */;
  373. }
  374.  
  375.  
  376. //
  377. //    FindNextModule
  378. //
  379. //        Search for the next module in the address range start to limit-2.  Module names immediately follow either
  380. //        an RTS, RTD (plus offset), or JMP (A0) instruction.  The three formats for legal module names are described
  381. //        in the header comments for ValidName.  If no module name found, return address of end of module where name
  382. //        would have been.  hasName parameter set to indicate whether a name was found.
  383. //
  384. //        return value    -    address of next module
  385. //
  386.  
  387. static UByte *FindNextModule (UByte *start, UByte *limit, Boolean *hasName, ReadMemFn readMemCallback, va_list args)
  388. {
  389.     UByte *fnEnd;
  390.     UByte *firstFollowingModule = NULL;
  391.  
  392.     while ((start < limit) && FindReturn (start, limit, &fnEnd, readMemCallback, args))
  393.         {
  394.         // After the call to FindReturn, fnEnd contains the address following the return instruction (either an RTS,
  395.         //    RTD, or JMP (A0)).  This will be the address of procedure name, if there is one.
  396.         //
  397.         if (firstFollowingModule == NULL)
  398.             firstFollowingModule = fnEnd;
  399.         
  400.         if (ValidName (fnEnd, readMemCallback, args))
  401.             {
  402.             // Found a module name, return its address.
  403.             //
  404.             *hasName = true;
  405.             return (fnEnd);
  406.             }
  407.         else
  408.             // Wasn't a valid name, keep looking starting after return instruction.
  409.             //
  410.             start = fnEnd;
  411.         }
  412.     
  413.     *hasName = false;
  414.     return firstFollowingModule;
  415. }
  416.  
  417.  
  418. //
  419. //    ValidName
  420. //
  421. //        Checks to see if the name at the pointer one of three valid formats for a module name.
  422. //
  423. //        The three formats are:
  424. //
  425. //            Variable length:    The first byte is in the range $80 to $9F and is a length in the
  426. //                                    range 0 to $1F. The high order bit must be set. A length of 0
  427. //                                    implies the second byte is the actual length in the range $01 
  428. //                                    thru $FF. The length byte(s) and name may be an odd number of
  429. //                                    bytes. However, the data after the name is word aligned.
  430. //            Fixed length 8:        The first byte is in the range $20 to $7F and is an ASCII character.
  431. //                                    The high order bit may be set but is not required to be.
  432. //            Fixed length 16:    The first byte is in the range $20 to $7F and is an ASCII character.
  433. //                                    The high order bit may be set but is not required to be.
  434. //                                    The high order bit in the second byte is required to be set.
  435. //                                    This distinguishes the two types of fixed names.
  436. //
  437.  
  438. static Boolean ValidName (UByte *name, ReadMemFn readMemCallback, va_list args)
  439. {
  440.     char        nameCopy[256];
  441.     UByte        *namePtr = (UByte*) nameCopy;
  442.     UWord        length;
  443.     Boolean        valid;
  444.  
  445.     if ((*readMemCallback) ((void *) name, 256, nameCopy, args) != kNoErr)
  446.         return false;
  447.     
  448.     valid = true;
  449.  
  450.     // The high order bit of the first byte of the name is set for variable length names.
  451.     //
  452.     if (*namePtr & 0x80)
  453.         {
  454.         length = *namePtr++ & 0x7F;
  455.  
  456.         // After clearing the high order bit, the first byte should be in the range of 0-1F, for variable
  457.         //    length names.  If the length is 0, the length is in the next byte.  The next byte should not be 0.
  458.         //
  459.         if (length == 0)
  460.             if (*namePtr)
  461.                 length = *namePtr++;
  462.             else
  463.                 valid = false;
  464.         else
  465.             // Maximum length if in the first byte is 1F.
  466.             //
  467.             if (length > 0x1F)
  468.                 valid = false;
  469.         
  470.         if (valid)
  471.             // So far the name is valid, loop through the name checking for the valid symbol characters 
  472.             //    'a'..'z', 'A'..'Z', '0'..'9', '_', '%', '.' (Variable length names cannot have spaces)
  473.             //    10/18/94 dkk
  474.             //    Added check to see that valid was still true. Used to set valid to whatever the last character
  475.             //    in name used to be.
  476.             //
  477.             for (;(length > 0) && valid; --length)
  478.                 if (valid)
  479.                     valid = LegalSymbolChar ((short) *namePtr++);
  480.         
  481.         }
  482.     else
  483.         {
  484.         //    High order bit in first byte of fixed length name may or may not be set.
  485.         //
  486.         valid = LegalTargetChar ((short) (*namePtr++ & 0x7F));
  487.         if (valid)
  488.  
  489.             {
  490.             // First character was legal, check the high order bit of the second byte to see whether it is a 8 byte or
  491.             // 16 byte fixed length name.
  492.             //
  493.             if (*namePtr & 0x80)
  494.             
  495.                 // 16 byte name.  Check the second character and set the length for the remaining 14 characters.
  496.                 //
  497.                 {
  498.                 valid = LegalTargetChar ((short) (*namePtr++ & 0x7F));
  499.                 length = 14;
  500.                 }
  501.             else
  502.                 // 8 byte name.  Check the second character and set the length for the remaining 6 characters.
  503.                 //
  504.                 {
  505.                 valid = LegalTargetChar ((short) *namePtr++);
  506.                 length = 6;
  507.                 }
  508.             
  509.             //    10/18/94 dkk
  510.             //    Added check to see that valid was still true. Used to set valid to whatever the last character
  511.             //    in name used to be.
  512.             //
  513.             for (;(length > 0) && valid; --length)
  514.                 if (valid)
  515.                     valid = LegalTargetChar ((short) *namePtr++);
  516.             }
  517.         }
  518.     return (valid);
  519. }
  520.     
  521.  
  522. //
  523. //    GetModuleName
  524. //
  525. //   Copy the valid MacsBug module name at address into the name string.
  526. //   Set dataStart to point to the first byte after the name after making sure it is word aligned.
  527. //   Set dataEnd to point to the first byte of the next procedure.
  528. //
  529.  
  530. static void GetModuleName (UByte *address, char *name, UByte **dataStart, UByte **dataEnd, ReadMemFn readMemCallback, va_list args)
  531. {
  532.     UWord        memWord;
  533.     UByte        ch, index;
  534.     char        nameCopy[kMaxNameLength];
  535.     UByte        *namePtr = (UByte*) nameCopy;
  536.  
  537.     *name = 0;
  538.     *dataStart = address;
  539.     *dataEnd = address;
  540.     
  541.     if ((*readMemCallback) ((void *) address, kMaxNameLength, nameCopy, args) != kNoErr)
  542.         return;
  543.  
  544.     // Read first character of name, stripping off most significant bit.
  545.     //
  546.     ch = *namePtr++ & 0x7F;
  547.  
  548.     // Variable length name, if value is 0 thru 1F.
  549.     //
  550.     if (ch < 0x20)
  551.         {
  552.         // The name is the new variable format. This may be a module or a method name.
  553.         //
  554.         if (ch == 0)
  555.             // Second byte is the actual length.
  556.             //
  557.             ch = *namePtr++;
  558.  
  559.         name[0] = 0;
  560.         for (index = 1; index <= ch; ++index)
  561.             // When the name gets over kMaxNameLength, truncate the name and just increment to the end of the name.
  562.             //
  563.             if (index <= kMaxNameLength)
  564.                 name[++name[0]] = *namePtr++;
  565.             else
  566.                 break;
  567.         
  568.         // The name may not be word aligned. Data after the name always starts on a word boundary.
  569.         //    10/18/94 dkk
  570.         //    Added additional 2 character offset to address. In translation from MacsBug my guess is the length
  571.         //    bytes were accidentally omitted. This caused a bug where the last character of the symbol name was
  572.         //    added to the symbol name address as the literal pool size. This caused the returned address range
  573.         //    to not contain the address we were interested in.
  574.         //
  575.         address += ch + 2;
  576.         if ((ULongWord) address % 2)
  577.             ++address;
  578.             
  579.         *dataStart = address;
  580.  
  581.         //    Variable format names are followed by a word which defines the length of the literal pool
  582.         //    after the code of this procedure and before the code of the next procedure. If the word is
  583.         //    odd then assume it is not a length.
  584.         //
  585.         if ((*readMemCallback) ((void *) address, sizeof(UWord), &memWord, args) != kNoErr)
  586.             return;
  587.         if (memWord & 1)
  588.             // Length word is odd, not the length.
  589.             //
  590.             *dataEnd = address;
  591.         else
  592.             // Add length word + length.
  593.             //
  594.             *dataEnd = address + 2 + memWord;
  595.  
  596.         name[name[0] + 1] = 0;            // terminating null to make it a TProtocolString
  597.         if (name[0] & 1)                // do we need a pad byte?
  598.             name[name[0] + 2] = 0;        // add one
  599.         }
  600.     else
  601.         {
  602.         // If the most significant bit of the second character is set, the name is the 16 byte class.method format,
  603.         // other wise its the 8 byte format.
  604.         //
  605.         if (*namePtr & 0x80)
  606.             {
  607.             //    The name is the 16 byte class.method format. Class and method are stored in reverse order in memory.
  608.             // Skip to byte 9 of the name to copy.  Address currently points to byte 2.
  609.             //
  610.             namePtr += 7;
  611.  
  612.             // Initialize length byte.
  613.             //
  614.             name[0] = 0;
  615.             
  616.             // Copy characters in the class.
  617.             //
  618.             for (index = 1; index <= 8; ++index)
  619.  
  620.                 // Strip the spaces used to pad to 8 characters.
  621.                 //
  622.                 if (*namePtr != ' ')
  623.                     name[++name[0]] = *namePtr++;
  624.                 else
  625.                     ++namePtr;
  626.  
  627.             //    Insert the '.' to indicate a method
  628.             //
  629.             name[++name[0]] = '.';
  630.             
  631.             // Reset pointer to beginning of the name.
  632.             //
  633.             namePtr -= 16;
  634.             
  635.             // Copy characters in method
  636.             //
  637.             for (index = 1; index <= 8; ++index)
  638.  
  639.                 // Strip the spaces used to pad to 8 characters.  First two bytes also have most significant bit set.
  640.                 //
  641.                 if (*namePtr & 0x7F != ' ')
  642.                     name[++name[0]] = *namePtr++ & 0x7F;
  643.                 else
  644.                     ++namePtr;
  645.  
  646.             // Skip to byte after end of name.
  647.             //
  648.             address += 16;
  649.             }
  650.         else
  651.             {
  652.             // 8 byte format.  Copy first character and initialize length byte.
  653.             //
  654.             name[1] = ch;
  655.             name[0] = 1;
  656.             
  657.             // Copy remaining characters in name.
  658.             //
  659.             for (index = 2; index <= 8; ++index)
  660.  
  661.                 // Strip the spaces used to pad to 8 characters.
  662.                 //
  663.                 if (*namePtr != ' ')
  664.                     name[++name[0]] = *namePtr++;
  665.                 else
  666.                     ++namePtr;
  667.  
  668.             // Skip to byte after end of name.
  669.             //
  670.             address += 8;
  671.             }
  672.  
  673.         //    Fixed length names do not indicate the data length. Assumed immediately after the name.
  674.         //
  675.         *dataStart = address;
  676.         *dataEnd = address;
  677.  
  678.         name[name[0] + 1] = 0;            // terminating null to make it a TProtocolString
  679.         if (name[0] & 1)                // do we need a pad byte?
  680.             name[name[0] + 2] = 0;        // add one
  681.         }
  682.     
  683. }
  684.  
  685.  
  686. //
  687. //    FindReturn
  688. //
  689. //        Search for an RTS, RTD or JMP (A0) instruction.  The address following the instruction is returned in afterReturn.
  690. //        Function value is true if return is found, false otherwise.
  691. //
  692. //        start                -    Address to start search for return.
  693. //        limit                -    Address to stop search for return.
  694. //        afterReturn        -    Address after return instruction (if found).
  695. //        return value    -    True if return is found, false otherwise.
  696. //
  697.  
  698. static Boolean FindReturn (UByte *start, UByte *limit, UByte **afterReturn, ReadMemFn readMemCallback, va_list args)
  699. {
  700.     UWord        memWord;
  701.     
  702.     while (start < limit)
  703.         {
  704.         if ((*readMemCallback) ((void *) start, sizeof(UWord), &memWord, args) != kNoErr)
  705.             return false;
  706.         
  707.         switch (memWord)
  708.             {
  709.             case kJMPA0:
  710.             case kRTS:
  711.                 *afterReturn = start + 2;            // JMP (A0) and RTS instruction are both two byte instructions
  712.                 return (true);
  713.                 break;
  714.     
  715.             case kRTD:
  716.                 *afterReturn = start + 4;            //    RTD is a four byte instruction.
  717.                 return (true);
  718.                 break;
  719.     
  720.             default:
  721.                 start += 2;
  722.                 break;
  723.             }
  724.         }
  725.         
  726.     return (false);
  727. }
  728.  
  729.  
  730. //
  731. //    LegalSymbolChar
  732. //
  733. //        Return True if ch is in the set ['a'..'z', 'A'..'Z', '0'..'9', '_', '%', '.']
  734. //
  735.  
  736. static Boolean LegalSymbolChar (short ch)
  737. {
  738.     return (((ch >= 'a') && (ch <= 'z')) ||
  739.                 ((ch >= 'A') && (ch <= 'Z')) ||
  740.                  ((ch >= '0') && (ch <= '9')) ||
  741.                   (ch == '_') || (ch == '%') || (ch == '.') ||
  742.                    (ch == '<') || (ch == '>') || (ch == ',')    // ・・・ [Edmark, PBE] added '<', '>', and ','
  743.                     );
  744. }
  745.  
  746.  
  747. //
  748. //    LegalTargetChar
  749. //
  750. //        Return True if ch is in the set ['a'..'z', 'A'..'Z', '0'..'9', '_', '%', '.', ' '].  Same as LegalSymbolChar
  751. //        except that a space is also a legal character.
  752. //
  753.  
  754. static Boolean LegalTargetChar (short ch)
  755. {
  756.     return (((ch >= 'a') && (ch <= 'z')) ||
  757.                 ((ch >= 'A') && (ch <= 'Z')) ||
  758.                  ((ch >= '0') && (ch <= '9')) ||
  759.                   (ch == '_') || (ch == '%') || (ch == '.') || (ch == ' ') ||
  760.                    (ch == '<') || (ch == '>') || (ch == ',')    // ・・・ [Edmark, PBE] added '<', '>', and ','
  761.                     );
  762. }
  763.  
  764.  
  765.